package org.infodavid.common.impl.services.helpers;

import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import org.infodavid.common.impl.services.validators.AbstractValidator;
import org.infodavid.common.model.validators.UniqueValidator;
import org.infodavid.common.persistence.IDataObject;
import org.infodavid.common.persistence.INamed;
import org.infodavid.common.services.IApplicationContext;
import org.infodavid.common.services.exception.DuplicatedEntityException;

/**
 * The Class ValidatorHelper: Helper class for validation
 * @param <T>
 */
public class ValidatorHelper<T> {

	/**
	 * Update application context.
	 * @param contextUdpated the context udpated
	 */
	public static void updateApplicationContext(IApplicationContext contextUdpated) {
		UniqueValidator.context = contextUdpated;
	}

	/**
	 * check null for list object
	 * @param objList
	 * @param errors
	 */
	public static void checkNull(final List<Object> objList, final List<String> errors) {
		if ((objList != null) && (errors != null) && (objList.size() == errors.size())) {

			for (int i = 0; i < objList.size(); i++) {
				if (objList.get(i) == null) {
					throw new IllegalArgumentException(errors.get(i));
				}
			}
		}
	}

	/**
	 * Validate key.
	 *
	 * @param <T> the generic type
	 * @param context the context
	 * @param items the items
	 * @param validator the validator
	 */
	public static <T extends IDataObject<Long>> void validateKey(final IApplicationContext context,
	    final Collection<T> items, final AbstractValidator<T> validator) {
		final Set<Long> keySet = new HashSet<Long>();

		if (items == null || items.size() == 0 || validator == null) {}
		else {
			final Iterator<T> ite = items.iterator();
			T item;

			while (ite.hasNext()) {
				item = ite.next();

				if (item == null) {
					throw new IllegalArgumentException(validator.getGenericType());
				}
				else if (item.getKey() == null) {
					validator.validate(context, item);
				}
				else if (keySet.contains(item.getKey())) {
					throw new DuplicatedEntityException(item.getClass(), item.getKey());
				}
				else {
					validator.validate(context, item);
					keySet.add(item.getKey());
				}
			}
		}
	}

	/**
	 * Validate key name.
	 *
	 * @param <T> the generic type
	 * @param context the context
	 * @param items the items
	 * @param validator the validator
	 */
	public static <T extends INamed & IDataObject<Long>> void validateKeyName(
	    final IApplicationContext context, final Collection<T> items,
	    final AbstractValidator<T> validator) {
		final Set<Long> keySet = new HashSet<Long>();

		if (items == null || items.size() == 0 || validator == null) {}
		else {
			final Iterator<T> ite = items.iterator();
			T item;

			while (ite.hasNext()) {
				item = ite.next();

				if (item == null) {
					throw new IllegalArgumentException(validator.getGenericType());
				}
				else if (item.getName() == null) {
					validator.validate(context, item);

					if (item.getKey() != null) {
						keySet.add(item.getKey());
					}
				}
				else if (item.getKey() == null) {
					validator.validate(context, item);
				}
				else if (keySet.contains(item.getKey())) {
					throw new DuplicatedEntityException(item.getClass(), item.getKey());
				}
				else {
					validator.validate(context, item);
					keySet.add(item.getKey());
				}
			}
		}
	}

	/**
	 * Validate key name not null.
	 *
	 * @param <T> the generic type
	 * @param context the context
	 * @param items the items
	 * @param validator the validator
	 */
	public static <T extends INamed & IDataObject<Long>> void validateKeyNameNotNull(
	    final IApplicationContext context, final Collection<T> items,
	    final AbstractValidator<T> validator) {
		final Set<String> stringSet = new HashSet<String>();
		final Set<Long> keySet = new HashSet<Long>();

		if (items == null || items.size() == 0) {}
		else {
			final Iterator<T> ite = items.iterator();
			T item;

			while (ite.hasNext()) {
				item = ite.next();

				if (item == null || item.getName() == null) {
					throw new IllegalArgumentException(validator.getGenericType());
				}
				else if (item.getKey() == null) {
					validator.validate(context, item);

					if (item.getName() != null) {
						stringSet.add(item.getName());
					}
				}
				else if (stringSet.contains(item.getName())) {
					throw new DuplicatedEntityException(item.getClass(), item.getName());
				}
				else if (keySet.contains(item.getKey())) {
					throw new DuplicatedEntityException(item.getClass(), item.getKey());
				}
				else {
					validator.validate(context, item);
					stringSet.add(item.getName());
					keySet.add(item.getKey());
				}
			}
		}
	}

	/**
	 * Validate key name dup.
	 *
	 * @param <T> the generic type
	 * @param context the context
	 * @param items the items
	 * @param validator the validator
	 */
	public static <T extends INamed & IDataObject<Long>> void validateKeyNameDup(
	    final IApplicationContext context, final Collection<T> items,
	    final AbstractValidator<T> validator) {
		final Set<String> stringSet = new HashSet<String>();
		final Set<Long> keySet = new HashSet<Long>();

		if (items == null || items.size() == 0) {}
		else {
			final Iterator<T> ite = items.iterator();
			T item;

			while (ite.hasNext()) {
				item = ite.next();

				if (item == null) {
					throw new IllegalArgumentException(validator.getGenericType());
				}
				else if (item.getName() == null) {
					validator.validate(context, item);

					if (item.getKey() != null) {
						keySet.add(item.getKey());
					}
				}
				else if (item.getKey() == null) {
					validator.validate(context, item);

					if (item.getName() != null) {
						stringSet.add(item.getName());
					}
				}
				else if (stringSet.contains(item.getName())) {
					throw new DuplicatedEntityException(item.getClass(), item.getName());
				}
				else if (keySet.contains(item.getKey())) {
					throw new DuplicatedEntityException(item.getClass(), item.getKey());
				}
				else {
					validator.validate(context, item);
					stringSet.add(item.getName());
					keySet.add(item.getKey());
				}
			}
		}

	}
}
